package gam.n1.areas;

import com.google.common.collect.Maps;
import gam.n1.e.a.AreaPreRunEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Constructor;
import java.util.*;

public final class AreaManager {
    private Plugin plugin;
    private final static Map<UUID, Area> AREAS = Collections.synchronizedMap(new LinkedHashMap<>());
    private final static Map<Area,BukkitTask> RUNNING_TASK = Collections.synchronizedMap(new LinkedHashMap<>());
    private static final Map<String,Class> REGISTER = Maps.newHashMap();
    private static final Map<String,Area> KEEP = Maps.newHashMap();
    private final Runnable SAFE_TASK = () -> {
        // Do Transportation inspection.
        if (!RUNNING_TASK.isEmpty()){
            HashMap<Area, BukkitTask> var1 = Maps.newHashMap(RUNNING_TASK);
            var1.forEach(($area, $task)->{
                if ($area.cD()){
                    if (!$task.isCancelled()) $task.cancel();
                    RUNNING_TASK.remove($area);
                    System.out.println("Noloading: " +$area.getAreaName());
                }
            });
        }
        if (!AREAS.isEmpty()){
            Collection<Area> var1 = AREAS.values();
            for (Area var2 : var1) {
                if (!var2.isRunning()){
                    RUNNING_TASK.put(var2,Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, var2::tick,0,20));
                    AREAS.remove(var2.getAreaUUID());
                    System.out.println("loading:" + var2.getAreaName());
                }
            }
        }
    };

    private BukkitTask MAIN_T;
    public AreaManager(@NotNull Plugin plugin){
        this.plugin = plugin;
    }
    public final void __RUN__(){
        if (MAIN_T == null){
            MAIN_T = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin,SAFE_TASK,0,20L);
        }
    }
    public final void __DIE__(){
        if (!MAIN_T.isCancelled()) MAIN_T.cancel();
        if (RUNNING_TASK.size() > 0){
            RUNNING_TASK.values().forEach(task -> {
                if (!task.isCancelled()) task.cancel();
            });
        }
    }
    public static void addArea(Area area){
        Objects.requireNonNull(area);
        String var1 = area.getAreaName();
        if (!area.isRunning()){
            KEEP.put(var1,area);
        }
    }
    public static Area findArea(String name){
        Objects.requireNonNull(name);
        return KEEP.get(name);
    }
    public static Class hasRegister(String n){
        return REGISTER.getOrDefault(n, null);
    }
    public static String hasRegister(Class<?> a){
        Objects.requireNonNull(a);
        for (String n : REGISTER.keySet()) {
            if (REGISTER.get(n) == a) {
                return n;
            }
        }
        return null;
    }
    public static boolean register(String areaKey,Class<?> areaClass) {
        Objects.requireNonNull(areaKey);
        Objects.requireNonNull(areaClass);
        if (Area.class.isAssignableFrom(areaClass)){
            if (!REGISTER.containsKey(areaKey)){
                REGISTER.putIfAbsent(areaKey, areaClass);
                return true;
            }
        }

        return false;
    }
    public static Area Build(@NotNull Plugin plugin,String key,String areaName) throws Exception {
        Objects.requireNonNull(key);
        Objects.requireNonNull(areaName);
        Class C =  REGISTER.get(key);
        System.out.println(C);
        if (C != null && Area.class.isAssignableFrom(C)){
            Constructor _c = C.getConstructor(Plugin.class, String.class);
            return (Area) _c.newInstance(plugin, areaName);
        }
        return null;
    }

    public static boolean j(Area area){
        Objects.requireNonNull(area);
        UUID var1 = area.getAreaUUID();
        if (!area.isRunning() && area.cI()){
            AREAS.put(var1,area);
            System.out.println("The area is join to the pre-Threat.");
            return true;
        }
        return false;
    }
    public static boolean iP(Player player){
        return com().values().stream().anyMatch(area -> area.playerInGame(player));
    }
    public static boolean iA(UUID uuid){
        return com().containsKey(uuid);
    }

    public static Map<UUID, Area> com(){
        return Collections.unmodifiableMap(AREAS);
    }
}
